<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>C语言基础 - 文件操作</title>
    <link rel="stylesheet" href="common.css">
    <style>
        /* 页面特有样式 */
        .file-card {
            background-color: #f5f9ff;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 25px;
            border-left: 4px solid #5D9CEC;
        }
        
        .io-box {
            background-color: #f0f7ff;
            padding: 15px;
            border-radius: 5px;
            margin: 15px 0;
        }
        
        .binary-box {
            background-color: #fff3e0;
            padding: 15px;
            border-radius: 5px;
            margin: 15px 0;
        }
        
        .position-box {
            background-color: #e8f5e9;
            padding: 15px;
            border-radius: 5px;
            margin: 15px 0;
        }
        
        .mode-table {
            width: 100%;
            margin: 15px 0;
            border-collapse: collapse;
        }
        
        .warning-note {
            background-color: #ffebee;
            border-left: 4px solid #f44336;
            padding: 12px;
            margin: 15px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>C语言基础入门课程</h1>
        </header>
        
        <nav>
            <a href="index.html">首页</a>
            <a href="02-intro.html">C语言简介与环境搭建</a>
            <a href="03-structure.html" class="current">C程序结构</a>
            <a href="04-datatypes.html">基本数据类型</a>
            <a href="05-variables.html">变量与常量</a>
            <a href="06-operators.html">运算符</a>
            <a href="07-io.html" class="current">输入输出</a>
            <a href="08-conditionals.html">条件语句</a>
            <a href="09-loops.html">循环结构</a>
            <a href="10-functions.html" class="current">函数基础</a>
            <a href="11-scope.html">作用域与存储类</a>
            <a href="12-recursion.html">递归函数</a>
            <a href="13-arrays.html">一维数组</a>
            <a href="14-multidim.html" class="current">多维数组</a>
            <a href="15-strings.html">字符串处理</a>
            <a href="16-pointers.html">指针基础</a>
            <a href="17-pointers_advanced.html" class="current">指针进阶</a>
            <a href="18-structs.html">结构体</a>
            <a href="19-files.html">文件操作</a>
            <a href="20-project.html">综合项目</a>
        </nav>
        
        <main>
            <h2>C语言文件操作</h2>
            
            <section>
                <h3>文件操作概述</h3>
                <p>文件操作是程序与外部存储设备交互的重要方式，包括文本文件和二进制文件的读写。</p>
            </section>
            
            <div class="file-card">
                <h3>1. 文件打开/关闭</h3>
                
                <div class="io-box">
                    <h4>fopen函数</h4>
                    <pre><code>FILE *fopen(const char *filename, const char *mode);</code></pre>
                    <p>打开文件成功返回文件指针，失败返回NULL</p>
                    
                    <h4>fclose函数</h4>
                    <pre><code>int fclose(FILE *stream);</code></pre>
                    <p>成功关闭返回0，失败返回EOF</p>
                </div>
                
                <table class="mode-table">
                    <tr>
                        <th>模式</th>
                        <th>描述</th>
                    </tr>
                    <tr>
                        <td>"r"</td>
                        <td>只读方式打开文本文件</td>
                    </tr>
                    <tr>
                        <td>"w"</td>
                        <td>只写方式创建/清空文本文件</td>
                    </tr>
                    <tr>
                        <td>"a"</td>
                        <td>追加方式打开文本文件</td>
                    </tr>
                    <tr>
                        <td>"rb"</td>
                        <td>只读方式打开二进制文件</td>
                    </tr>
                    <tr>
                        <td>"wb"</td>
                        <td>只写方式创建/清空二进制文件</td>
                    </tr>
                    <tr>
                        <td>"ab"</td>
                        <td>追加方式打开二进制文件</td>
                    </tr>
                    <tr>
                        <td>"r+"</td>
                        <td>读写方式打开文本文件</td>
                    </tr>
                    <tr>
                        <td>"w+"</td>
                        <td>读写方式创建/清空文本文件</td>
                    </tr>
                    <tr>
                        <td>"a+"</td>
                        <td>读写方式打开/创建文本文件(追加)</td>
                    </tr>
                </table>
                
                <div class="warning-note">
                    <h4>文件打开最佳实践</h4>
                    <ul>
                        <li>总是检查fopen返回值是否为NULL</li>
                        <li>操作完成后立即关闭文件</li>
                        <li>使用相对路径或绝对路径指定文件位置</li>
                    </ul>
                </div>
                
                <div class="example-box">
                    <h4>基本文件操作示例</h4>
                    <pre><code>#include &lt;stdio.h&gt;

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        printf("文件打开失败\n");
        return 1;
    }
    
    // 文件操作...
    
    fclose(file);
    return 0;
}</code></pre>
                </div>
            </div>
            
            <div class="file-card">
                <h3>2. 文本文件操作</h3>
                
                <div class="io-box">
                    <h4>格式化写入(fprintf)</h4>
                    <pre><code>int fprintf(FILE *stream, const char *format, ...);
// 示例:
fprintf(file, "姓名: %s, 年龄: %d\n", name, age);</code></pre>
                    
                    <h4>格式化读取(fscanf)</h4>
                    <pre><code>int fscanf(FILE *stream, const char *format, ...);
// 示例:
while (fscanf(file, "%s %d", name, &amp;age) != EOF) {
    printf("读取: %s %d\n", name, age);
}</code></pre>
                </div>
                
                <div class="io-box">
                    <h4>字符/行读写</h4>
                    <pre><code>// 字符读写
int fputc(int c, FILE *stream);
int fgetc(FILE *stream);

// 行读写
char *fgets(char *str, int n, FILE *stream);
int fputs(const char *str, FILE *stream);</code></pre>
                    
                    <h4>示例：文件复制</h4>
                    <pre><code>void copyFile(const char *src, const char *dest) {
    FILE *fsrc = fopen(src, "r");
    FILE *fdest = fopen(dest, "w");
    
    if (fsrc == NULL || fdest == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    int c;
    while ((c = fgetc(fsrc)) != EOF) {
        fputc(c, fdest);
    }
    
    fclose(fsrc);
    fclose(fdest);
}</code></pre>
                </div>
            </div>
            
            <div class="file-card">
                <h3>3. 二进制文件操作</h3>
                
                <div class="binary-box">
                    <h4>块读写(fread/fwrite)</h4>
                    <pre><code>size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);</code></pre>
                    
                    <h4>示例：结构体数组读写</h4>
                    <pre><code>struct Student {
    int id;
    char name[20];
    float score;
};

// 写入结构体数组
struct Student students[3] = {
    {1001, "张三", 89.5f},
    {1002, "李四", 92.0f},
    {1003, "王五", 78.5f}
};

FILE *file = fopen("students.dat", "wb");
if (file != NULL) {
    fwrite(students, sizeof(struct Student), 3, file);
    fclose(file);
}

// 读取结构体数组
struct Student readStudents[3];
file = fopen("students.dat", "rb");
if (file != NULL) {
    fread(readStudents, sizeof(struct Student), 3, file);
    fclose(file);
}</code></pre>
                </div>
                
                <div class="warning-note">
                    <h4>二进制文件注意事项</h4>
                    <ul>
                        <li>二进制文件不可直接查看内容</li>
                        <li>跨平台使用时注意字节序问题</li>
                        <li>结构体中的指针成员不能直接写入文件</li>
                    </ul>
                </div>
            </div>
            
            <div class="file-card">
                <h3>4. 文件位置指针</h3>
                
                <div class="position-box">
                    <h4>定位函数</h4>
                    <pre><code>int fseek(FILE *stream, long offset, int origin);
void rewind(FILE *stream);
long ftell(FILE *stream);</code></pre>
                    
                    <h4>origin参数取值</h4>
                    <ul>
                        <li>SEEK_SET - 文件开头</li>
                        <li>SEEK_CUR - 当前位置</li>
                        <li>SEEK_END - 文件末尾</li>
                    </ul>
                </div>
                
                <div class="position-box">
                    <h4>示例：随机访问文件</h4>
                    <pre><code>// 读取第3个学生记录(从0开始)
FILE *file = fopen("students.dat", "rb");
if (file != NULL) {
    struct Student stu;
    
    // 定位到第3条记录
    fseek(file, 2 * sizeof(struct Student), SEEK_SET);
    
    // 读取记录
    fread(&amp;stu, sizeof(struct Student), 1, file);
    printf("学号: %d, 姓名: %s\n", stu.id, stu.name);
    
    // 回到文件开头
    rewind(file);
    
    // 获取当前位置
    long pos = ftell(file);
    printf("当前位置: %ld\n", pos);
    
    fclose(file);
}</code></pre>
                </div>
                
                <div class="warning-note">
                    <h4>注意事项</h4>
                    <ul>
                        <li>文本模式下fseek/ftell可能不准确</li>
                        <li>二进制模式下偏移量应为sizeof的整数倍</li>
                        <li>超出文件范围的定位是未定义行为</li>
                    </ul>
                </div>
            </div>
            
            <section>
                <h3>综合示例：学生成绩管理系统</h3>
                <pre><code>#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

typedef struct {
    int id;
    char name[20];
    float score;
} Student;

void saveToFile(Student *students, int count, const char *filename) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fwrite(students, sizeof(Student), count, file);
    fclose(file);
}

int loadFromFile(Student *students, const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        printf("文件打开失败\n");
        return 0;
    }
    
    // 获取文件大小
    fseek(file, 0, SEEK_END);
    long size = ftell(file);
    rewind(file);
    
    int count = size / sizeof(Student);
    fread(students, sizeof(Student), count, file);
    
    fclose(file);
    return count;
}

int main() {
    Student class[5] = {
        {1001, "张三", 89.5f},
        {1002, "李四", 92.0f},
        {1003, "王五", 78.5f},
        {1004, "赵六", 85.0f},
        {1005, "钱七", 90.5f}
    };
    
    // 保存到文件
    saveToFile(class, 5, "students.dat");
    
    // 从文件加载
    Student loaded[5];
    int count = loadFromFile(loaded, "students.dat");
    
    // 显示加载的数据
    printf("从文件加载的学生数据:\n");
    for (int i = 0; i < count; i++) {
        printf("%d\t%s\t%.1f\n", 
               loaded[i].id, loaded[i].name, loaded[i].score);
    }
    
    return 0;
}</code></pre>
            </section>
        </main>
        
        <footer>
             <p>&copy; </p>
        </footer>
        
        <!-- 二维码区域 -->

    </div> <!-- 结束.container -->
</body>
</html>